/*!
 * Squid 总结、积累、收集的一些基础方法
 * http://www.cnblogs.com/typeof/
 *
 * 所有plugins、swing所做的扩展都是基于Squid对象
 */
(function (window) {
  //定义squid
  var Squid = function () {
    },
    slice = Array.prototype.slice,
    splice = Array.prototype.splice,
    trim = String.prototype.trim;

  //浅度拷贝
  Squid.extend = function () {
    var target = arguments[0],
      i = 1,
      length = arguments.length,
      options,
      prop;

    if (typeof target !== 'object') {
      target = {};
    }

    if (length === i) {
      target = this;
      --i;
    }

    for (; i < length; i++) {
      if ((options = arguments[i]) != null) {
        for (prop in options) {
          target[prop] = options[prop];
        }
      }
    }

    return target;
  };

  //DOM 方法
  Squid.extend({
    getElementById: function (id) {
      var elem = document.getElementById(id);

      if (elem && elem.parentNode) {
        if (elem.id !== id) {
          elem = null;
          var elems = document.getElementsByTagName(id),
            i = 0,
            length = elems.length,
            cur;

          for (; i < length; i++) {
            cur = elems[i];
            if (cur.id === id) {
              elem = cur;
              break;
            }
          }
        }

        return elem;
      }
    },
    getElementsByTagName: function (tagName, context) {
      context = context || document;

      var elems = context.getElementsByTagName(tagName),
        r = [];

      try {
        r = slice.call(elems, 0);
      } catch (e) {
        var i = 0,
          length = elems.length,
          elem;

        for (; i < length; i++) {
          elem = elems[i];
          r.push(elem);
        }
      }

      return r;
    },
    getElementsByClassName: function (className, context) {
      //执行上下文，默认为document
      context = context || document;

      var r = [];

      if (context.getElementsByClassName) {
        var elems = context.getElementsByClassName(className);
        r = slice.call(elems, 0);
      } else {
        var elems,
          elem,
          i = 0,
          length;

        elems = context.getElementsByTagName('*');
        length = elems.length;
        for (; i < length; i++) {
          elem = elems[i];
          if (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(className) >= 0) {
            r.push(elem);
          }
        }
      }

      return r;
    },
    children: function (elem) {

    },
    first: function (elem) {
      return this.sibling(elem.firstChild)[0];
    },
    next: function (elem) {
      return this.nth(elem, 2, 'nextSibling');
    },
    siblings: function (elem) {
      return this.sibling(elem.parentNode.firstChild, elem);
    },
    nth: function (cur, r, dir) {
      r = r || 1;
      var i = 0;

      for (; cur; cur = cur[dir]) {
        if (cur.nodeType === 1 && ++i === r) {
          break;
        }
      }

      return cur;
    },
    sibling: function (n, elem) {
      var r = [];

      for (; n; n = n.nextSibling) {
        if (n.nodeType === 1 && n !== elem) {
          r.push(n);
        }
      }

      return r;
    },
    isVisible: function (elem) {
      return !this.isHidden(elem);
    },
    isHidden: function (elem) {
      if (elem) {
        var width = elem.offsetWidth,
          height = elem.offsetHeight;

        return (width === 0 && height === 0) || elem.style.display === 'none'
      }
    },
    getOffset: function (elem) {
      var body = document.body,
        docElem = document.documentElement;

      if ('getBoundingClientRect' in document.documentElement) {
        var box;

        try {
          box = elem.getBoundingClientRect()
        } catch (e) {
        }

        if (!box || !elem.parentNode) {
          return box ? {top: box.top, left: box.left} : {top: 0, left: 0}
        }

        var win = window,
          clientTop = docElem.clientTop || body.clientTop || 0,
          clientLeft = docElem.clientLeft || body.clientLeft || 0,
          scrollTop = win.pageYOffset || docElem.scrollTop || body.scrollTop,
          scrollLeft = win.pageXOffset || docElem.scrollLeft || body.scrollLeft,
          top = box.top + scrollTop - clientTop,
          left = box.left + scrollLeft - clientLeft;

        return {top: top, left: left}
      } else {
        var offsetParent = elem.offsetParent,
          top = elem.offsetTop,
          left = elem.offsetLeft;

        while ((elem = elem.parentNode) && elem !== body && elem !== docElem) {
          if (elem === offsetParent) {
            top = elem.offsetTop
            left = elem.offsetLeft

            offsetParent = elem.offsetParent
          }
        }

        return {top: top, left: left}
      }
    },
    position: function (elem) {
      if (!elem) {
        return null;
      }

      var offsetParent = elem.offsetParent,
        offset = this.getOffset(elem),
        parentOffset = this.getOffset(offsetParent);

      return {
        top: offset.top - parentOffset.top,
        left: offset.left - parentOffset.left
      };
    }
  });

  //全局缓存对象
  var cache = {};

  Squid.extend({
    guid: 1,
    uuid: 0,
    expando: 'squid' + (Math.random() + '').replace(/\D/g, ''),
    data: function (elem, name) {
      var internalKey = squid.expando,
        id,
        thisCache,
        r;

      id = elem[squid.expando];
      if (!id) {
        elem[squid.expando] = id = ++squid.uuid;
      }
      if (!cache[id]) {
        cache[id] = {};
      }

      if (typeof name === 'object' || typeof name === 'function') {
        cache[id][internalKey] = name;
      }

      thisCache = cache[id];

      if (!thisCache[internalKey]) {
        thisCache[internalKey] = {};
      }
      thisCache = thisCache[internalKey];

      if (name === 'events' && !thisCache[name]) {
        return thisCache[internalKey] && thisCache[internalKey].events;
      }

      if (typeof name === 'string') {
        r = thisCache[name];
      } else {
        r = thisCache;
      }

      return r;
    },
    removeData: function (elem, name) {
      var internalKey = squid.expando,
        id = elem[squid.expando],
        internalCache;

      if (!cache[id]) {
        return;
      }
      try {
        delete cache[id];
      } catch (e) {
        cache[id] = null;
      }
      if (elem.removeAttribute) {
        elem.removeAttribute(squid.expando);
      } else {
        elem[squid.expando] = null;
      }
    }
  });

  //事件处理
  Squid.event = {
    add: function (elem, type, handler) {
      var elemData,
        events,
        eventHandler,
        handleObj,
        handlers;

      if (elem.nodeType === 3 || elem.nodeType === 8) {
        return;
      }
      if (!handler) {
        return;
      }
      if (!handler.guid) {
        handler.guid = squid.guid++;
      }

      elemData = squid.data(elem);
      if (!elemData) {
        return;
      }

      events = elemData.events;
      eventHandler = elemData.handle;
      if (!events) {
        elemData.events = events = {};
      }

      if (!eventHandler) {
        elemData.handle = eventHandler = function (event) {
          return squid.event.handle.apply(eventHandler.elem, arguments);
        };
        eventHandler.elem = elem;
      }

      handleObj = {
        handler: handler
      };
      handleObj.type = type;
      if (!handleObj.guid) {
        handleObj.guid = handler.guid;
      }
      handlers = events[type];
      if (!handlers) {
        handlers = events[type] = [];
        if (elem.addEventListener) {
          elem.addEventListener(type, eventHandler, false);
        } else if (elem.attachEvent) {
          elem.attachEvent('on' + type, eventHandler);
        }
      }

      handlers.push(handleObj);
    },
    remove: function (elem, type, handler) {
      var elemData,
        events,
        eventType,
        i = 0,
        handleObj;

      if (elem.nodeType === 3 || elem.nodeType === 8) {
        return;
      }

      elemData = squid.data(elem);
      events = elemData.events;
      if (!events) {
        return;
      }
      eventType = events[type] || [];
      if (!handler) {
        for (; i < eventType.length; i++) {
          handleObj = eventType[i];
          squid.event.remove(elem, type, handleObj.handler);
          eventType.splice(i--, 1);
        }
      }

      if (eventType.length === 0) {
        if (elem.removeEventListener) {
          elem.removeEventListener(type, elemData.handle, false);
        } else if (elem.detachEvent) {
          elem.detachEvent('on' + type, elemData.handle);
        }
      }

      squid.removeData(elem);
    },
    handle: function (event) {
      var i = 0,
        length,
        handlers,
        handleObj,
        args = Array.prototype.slice.call(arguments, 0);

      event = squid.event.fix(event);
      handlers = ((squid.data(this, 'events') || {})[event.type] || []).slice(0);

      args[0] = event;

      length = handlers.length;
      for (; i < length; i++) {
        handleObj = handlers[i];
        event.handler = handleObj.handler;
        event.handleObj = handleObj;

        handleObj.handler.apply(this, args);
      }
    },
    fix: function (event) {
      if (!event.target) {
        event.target = event.srcElement || document;
      }

      if (event.target.nodeType === 3) {
        event.target = event.target.parentNode;
      }

      if (!event.relateTarget && event.fromElement) {
        event.relateTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
      }

      if (!event.preventDefault) {
        event.preventDefault = function () {
          event.returnValue = false;
        };
      }

      if (!event.stopPropagation) {
        event.stopPropagation = function () {
          event.cancelBubble = true;
        };
      }

      if (event.pageX == null) {
        var eventDoc = event.target.ownerDocument || document,
          doc = eventDoc.documentElment,
          body = eventDoc.body;

        event.pageX = event.clientX + (doc && document.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
        event.pageY = event.clientY + (doc && document.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
      }

      return event;
    }
  };

  //事件处理
  Squid.extend({
    on: function (elem, type, handler) {
      return this.event.add(elem, type, handler);
    },
    off: function (elem, type, handler) {
      return this.event.remove(elem, type, handler);
    },
    //把函数放到特定上下文执行
    proxy: function (fn, context) {
      var slice = Array.prototype.slice,
        args = slice.call(arguments, 2),
        proxy = function () {
          return fn.apply(context, args.concat(slice.call(arguments)));
        };

      proxy.guid = fn.guid = fn.guid || proxy.guid || squid.guid++;

      return proxy;
    }
  });

  var fnThrottleId = 0;
  //工具函数
  Squid.extend({
    trim: trim ? function (text) {
      return trim.call(text);
    } : function (text) {
      return text.toString().replace(/^\s+/, '').replace(/\s+$/, '');
    },
    throttle: function (fn, delay, context) {
      delay = delay || 100;
      context = context || null;

      return function () {
        var args = arguments;

        clearTimeout(fnThrottleId);
        fnThrottleId = setTimeout(function () {
          fn.apply(context, args);
        }, delay);
      };
    },
    isEmpty: function (obj) {
      for (var prop in obj) {
        return false;
      }

      return true;
    }
  });

  //基于Squid扩展的插件
  Squid.plugin = function () {
  };
  //解决浏览器对默认组件渲染不一样
  Squid.swing = function () {
  };
  window.squid = Squid;
})(window);